package online.longzipeng.cinemasys.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import online.longzipeng.cinemasys.common.exception.AppException;
import online.longzipeng.cinemasys.common.result.ResponseEnum;
import online.longzipeng.cinemasys.common.utils.ExceptionUtils;
import online.longzipeng.cinemasys.common.utils.Md5Utils;
import online.longzipeng.cinemasys.config.JWTConfig;
import online.longzipeng.cinemasys.dto.customer.CustomerLoginResponseDTO;
import online.longzipeng.cinemasys.dto.customer.CustomerQueryResponseDTO;
import online.longzipeng.cinemasys.entity.Customer;
import online.longzipeng.cinemasys.mapper.CustomerMapper;
import online.longzipeng.cinemasys.service.CustomerService;
import online.longzipeng.cinemasys.service.EmailService;
import online.longzipeng.cinemasys.vo.customer.CustomerChangePassWordByEmailVO;
import online.longzipeng.cinemasys.vo.customer.CustomerChangePasswordVO;
import online.longzipeng.cinemasys.vo.customer.CustomerLoginVO;
import online.longzipeng.cinemasys.vo.customer.CustomerQueryVO;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author lzp
 * @since 2021-04-09
 */
@Service
public class CustomerServiceImpl extends ServiceImpl<CustomerMapper, Customer> implements CustomerService {

    @Autowired
    CustomerMapper customerMapper;
    @Autowired
    JWTConfig jwtConfig;
    @Autowired
    RedisTemplate redisTemplate;
    @Autowired
    EmailService emailService;

    @Override
    public void add(Customer customer) {
        // 账号校验
        ExceptionUtils.isNull(findByUserName(customer.getUserName()),"该用户名已存在！！");
        // 加密
        customer.setPassword(Md5Utils.encrypt(customer.getPassword()));
        save(customer);
    }

    @Override
    public void updateCustomer(Customer customer) {
        if (!StringUtils.isEmpty(customer.getUserName()) && !customer.getUserName().equals(getById(customer.getId()).getUserName())) {
            // 账号校验
            ExceptionUtils.isNull(findByUserName(customer.getUserName()),"该用户名已存在！！");
        }
        // 密码加密
        if (customer.getPassword() != null) {
            customer.setPassword(Md5Utils.encrypt(customer.getPassword()));
        }
        updateById(customer);
    }

    @Override
    public void changePassword(CustomerChangePasswordVO customerChangePasswordVO) {
        // 数据校验
        ExceptionUtils.isNotNull(customerChangePasswordVO,"用户不能为空！！");
        ExceptionUtils.isNotNull(customerChangePasswordVO.getId(),"id不能为空！！");
        ExceptionUtils.isNotBlank(customerChangePasswordVO.getOldPassword(),"旧密码不能为空！！");
        ExceptionUtils.isNotBlank(customerChangePasswordVO.getNewPassword(),"新密码不能为空！！");
        // 修改密码
        Customer customer = getById(customerChangePasswordVO.getId());
        ExceptionUtils.isNotNull(customer,"用户不存在！！");
        ExceptionUtils.isTrue(Md5Utils.checkPassword(customerChangePasswordVO.getOldPassword(),customer.getPassword()),
                "旧密码输入错误！！");
        customer.setPassword(Md5Utils.encrypt(customerChangePasswordVO.getNewPassword()));
        updateById(customer);
    }

    @Override
    public IPage<CustomerQueryResponseDTO> getListPage(CustomerQueryVO queryVO) {
        Page<CustomerQueryResponseDTO> customerPage = new Page<>(queryVO.getPage(),queryVO.getSize());
        QueryWrapper<CustomerQueryResponseDTO> qwCustomer = new QueryWrapper<>();
        // 先判断查询类型 判断查询条件 用户名 昵称  状态 排序
        if (queryVO.getSearchType()) {
            qwCustomer.like(!StringUtils.isEmpty(queryVO.getUserName()),"user_name",queryVO.getUserName());
            qwCustomer.like(!StringUtils.isEmpty(queryVO.getNick()),"nick",queryVO.getNick());
            qwCustomer.eq(!StringUtils.isEmpty(queryVO.getStatus()),"status",queryVO.getStatus());
        }else {
            qwCustomer.or().like(!StringUtils.isEmpty(queryVO.getUserName()),"user_name",queryVO.getUserName());
            qwCustomer.or().like(!StringUtils.isEmpty(queryVO.getNick()),"nick",queryVO.getNick());
            qwCustomer.or().eq(!StringUtils.isEmpty(queryVO.getStatus()),"status",queryVO.getStatus());
        }
        // 判断排序
        if ("desc".equals(queryVO.getSort())) {
            qwCustomer.orderByDesc("id");
        }else {
            qwCustomer.orderByAsc("id");
        }
        return customerMapper.getListPage(customerPage,qwCustomer);
    }

    @Override
    public Customer findByUserName(String userName) {
        QueryWrapper<Customer> qwCustomer = new QueryWrapper<>();
        qwCustomer.eq("user_name",userName);
        return getOne(qwCustomer);
    }

    @Override
    public CustomerQueryResponseDTO findById(Long id) {
        return customerMapper.findById(id);
    }

    @Override
    public CustomerLoginResponseDTO login(CustomerLoginVO customerLoginVO, HttpServletRequest httpServletRequest) {
        // 通过用户名查询用户
        Customer customer = findByUserName(customerLoginVO.getUserName());
        // 判断用户是否存在
        ExceptionUtils.isNotNull(customer,ResponseEnum.USER_LOGIN_ERROR,null);
        // 判断密码
        ExceptionUtils.isTrue(Md5Utils.checkPassword(customerLoginVO.getPassword(),customer.getPassword()),ResponseEnum.USER_LOGIN_ERROR,null);
        // 判断状态
        if (customer.getStatus().equals(0)) {
            throw new AppException(ResponseEnum.USER_DISABLE);
        }else if (customer.getStatus().equals(2)){
            throw new AppException(ResponseEnum.USER_LOCKED);
        }
        // 设置登录ip和时间
        customer.setLastLoginIp(httpServletRequest.getRemoteAddr());
        customer.setLastLoginTime(LocalDateTime.now());
        updateById(customer);
        // 加密生成token对象返回用户
        CustomerLoginResponseDTO customerLoginResponseDTO = new CustomerLoginResponseDTO();
        BeanUtils.copyProperties(customer,customerLoginResponseDTO);
        customerLoginResponseDTO.setToken(jwtConfig.generateJwtWeb(customerLoginResponseDTO));
        return customerLoginResponseDTO;
    }

    @Override
    public CustomerQueryResponseDTO getUserInfo(String token) {
        CustomerLoginResponseDTO customerLoginResponseDTO = jwtConfig.checkJwtWeb(token);
        return findById(customerLoginResponseDTO.getId());
    }

    @Override
    public void getResetCode(String userName,String email) {
        // 先验证该用户的邮箱是否正确
        QueryWrapper<Customer> qwCustomer = new QueryWrapper<>();
        qwCustomer.eq("user_name",userName);
        Customer customer = getOne(qwCustomer);
        if (customer == null) {
            throw new AppException(ResponseEnum.USER_IS_NOT_EXISTED);
        }
        if (!customer.getEmail().equals(email)) {
            throw new AppException(ResponseEnum.USER_EMAIL_NOT_MATCHED);
        }

        if (email.matches("^$|^\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*$")) {
            int code = (int)(Math.random()*9999)+1;
            // 设置五分钟有效的验证码
            redisTemplate.opsForValue().set(email,code+"",300, TimeUnit.SECONDS);
            emailService.sendSimpleMail(email,"影院系统通知您正在进行重置密码操作","您的验证码是： "+code);
        }else {
            throw new AppException(ResponseEnum.EMAIL_FORMAT_ERROR);
        }
    }

    @Override
    public void changePasswordByEmailCheck(CustomerChangePassWordByEmailVO customerChangePassWordByEmailVO) {
        String code = (redisTemplate.opsForValue().get(customerChangePassWordByEmailVO.getEmail())).toString();
        if (StringUtils.isEmpty(code) ) {
            throw new AppException(ResponseEnum.EMAIL_CODE_NOT_EXIST);
        }else {
            // 验证验证码是否正确
            if (code.equals(customerChangePassWordByEmailVO.getCode())) {
                QueryWrapper<Customer> qwCustomer = new QueryWrapper<>();
                qwCustomer.eq("user_name",customerChangePassWordByEmailVO.getUserName());
                Customer customer = getOne(qwCustomer);
                if (customer == null) {
                    throw new AppException(ResponseEnum.USER_IS_NOT_EXISTED);
                }else {
                    customer.setPassword(Md5Utils.encrypt(customerChangePassWordByEmailVO.getPassword()));
                    updateById(customer);
                }
            }else {
                throw new AppException(ResponseEnum.EMAIL_CODE_ERROR);
            }
        }
    }
}
